1   package org.apache.lucene.index;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.apache.lucene.util.Counter;
23  import org.apache.lucene.util.IntBlockPool;
24  import org.apache.lucene.util.LuceneTestCase;
25  import org.apache.lucene.util.RamUsageEstimator;
26  
27  /**
28   * tests basic {@link IntBlockPool} functionality
29   */
30  public class TestIntBlockPool extends LuceneTestCase {
31    
32    public void testSingleWriterReader() {
33      Counter bytesUsed = Counter.newCounter();
34      IntBlockPool pool = new IntBlockPool(new ByteTrackingAllocator(bytesUsed));
35      
36      for (int j = 0; j < 2; j++) {
37        IntBlockPool.SliceWriter writer = new IntBlockPool.SliceWriter(pool);
38        int start = writer.startNewSlice();
39        int num = atLeast(100);
40        for (int i = 0; i < num; i++) {
41          writer.writeInt(i);
42        }
43        
44        int upto = writer.getCurrentOffset();
45        IntBlockPool.SliceReader reader = new IntBlockPool.SliceReader(pool);
46        reader.reset(start, upto);
47        for (int i = 0; i < num; i++) {
48          assertEquals(i, reader.readInt());
49        }
50        assertTrue(reader.endOfSlice());
51        if (random().nextBoolean()) {
52          pool.reset(true, false);
53          assertEquals(0, bytesUsed.get());
54        } else {
55          pool.reset(true, true);
56          assertEquals(IntBlockPool.INT_BLOCK_SIZE
57              * RamUsageEstimator.NUM_BYTES_INT, bytesUsed.get());
58        }
59      }
60    }
61    
62    public void testMultipleWriterReader() {
63      Counter bytesUsed = Counter.newCounter();
64      IntBlockPool pool = new IntBlockPool(new ByteTrackingAllocator(bytesUsed));
65      for (int j = 0; j < 2; j++) {
66        List<StartEndAndValues> holders = new ArrayList<>();
67        int num = atLeast(4);
68        for (int i = 0; i < num; i++) {
69          holders.add(new StartEndAndValues(random().nextInt(1000)));
70        }
71        IntBlockPool.SliceWriter writer = new IntBlockPool.SliceWriter(pool);
72        IntBlockPool.SliceReader reader = new IntBlockPool.SliceReader(pool);
73        
74        int numValuesToWrite = atLeast(10000);
75        for (int i = 0; i < numValuesToWrite; i++) {
76          StartEndAndValues values = holders
77              .get(random().nextInt(holders.size()));
78          if (values.valueCount == 0) {
79            values.start = writer.startNewSlice();
80          } else {
81            writer.reset(values.end);
82          }
83          writer.writeInt(values.nextValue());
84          values.end = writer.getCurrentOffset();
85          if (random().nextInt(5) == 0) {
86            // pick one and reader the ints
87            assertReader(reader, holders.get(random().nextInt(holders.size())));
88          }
89        }
90        
91        while (!holders.isEmpty()) {
92          StartEndAndValues values = holders.remove(random().nextInt(
93              holders.size()));
94          assertReader(reader, values);
95        }
96        if (random().nextBoolean()) {
97          pool.reset(true, false);
98          assertEquals(0, bytesUsed.get());
99        } else {
100         pool.reset(true, true);
101         assertEquals(IntBlockPool.INT_BLOCK_SIZE
102             * RamUsageEstimator.NUM_BYTES_INT, bytesUsed.get());
103       }
104     }
105   }
106   
107   private static class ByteTrackingAllocator extends IntBlockPool.Allocator {
108     private final Counter bytesUsed;
109     
110     public ByteTrackingAllocator(Counter bytesUsed) {
111       this(IntBlockPool.INT_BLOCK_SIZE, bytesUsed);
112     }
113     
114     public ByteTrackingAllocator(int blockSize, Counter bytesUsed) {
115       super(blockSize);
116       this.bytesUsed = bytesUsed;
117     }
118     
119     @Override
120     public int[] getIntBlock() {
121       bytesUsed.addAndGet(blockSize * RamUsageEstimator.NUM_BYTES_INT);
122       return new int[blockSize];
123     }
124     
125     @Override
126     public void recycleIntBlocks(int[][] blocks, int start, int end) {
127       bytesUsed
128           .addAndGet(-((end - start) * blockSize * RamUsageEstimator.NUM_BYTES_INT));
129     }
130     
131   }
132   
133   private void assertReader(IntBlockPool.SliceReader reader,
134       StartEndAndValues values) {
135     reader.reset(values.start, values.end);
136     for (int i = 0; i < values.valueCount; i++) {
137       assertEquals(values.valueOffset + i, reader.readInt());
138     }
139     assertTrue(reader.endOfSlice());
140   }
141   
142   private static class StartEndAndValues {
143     int valueOffset;
144     int valueCount;
145     int start;
146     int end;
147     
148     public StartEndAndValues(int valueOffset) {
149       this.valueOffset = valueOffset;
150     }
151     
152     public int nextValue() {
153       return valueOffset + valueCount++;
154     }
155     
156   }
157   
158 }